﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using PontoAtividadeUtilidades;
using System.Collections;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Xml.Xsl;
using PontoAtividadeReportDotNet.classeBasica;


namespace PontoAtividadeReportDotNet
{
    public sealed class RelatorioAtividade
    {
        public static String gerarRelatorioHTML(DateTime dataInicial, DateTime dataFinal)
        {
            String nomeArquivoHTMLFormatado = null;

            IList<ArquivoLogPonto> listaArquivosLog = obterListaArquivosLog(dataInicial, dataFinal);

            if (listaArquivosLog.Count == 0)
            {
                throw (new FileNotFoundException("Nenhum arquivo de log foi encontrado para o período " +
                                                 Util.formatarData(dataInicial, Constantes.FORMATO_DATA_COM_BARRAS) + " a " +
                                                 Util.formatarData(dataFinal, Constantes.FORMATO_DATA_COM_BARRAS)));
            }
            else 
            {
                String dataInicialFormatada = Util.formatarData(dataInicial, Constantes.FORMATO_DATA_SEM_BARRAS);
                String dataFinalFormatada = Util.formatarData(dataFinal, Constantes.FORMATO_DATA_SEM_BARRAS);

                String[] linhasXSL = File.ReadAllLines(Constantes.ARQUIVO_XSL);

                String xslMarkup = "";
                foreach (String linha in linhasXSL)
                {
                    xslMarkup = xslMarkup + " " + linha;
                }

                XDocument xmlTree = new XDocument(new XDeclaration(Constantes.DECLARACAO_VERSAO_XML, Constantes.DECLARACAO_CODIFICACAO_XML, Constantes.DECLARACAO_STANDALONE_YES), gerarXml(listaArquivosLog));

                XDocument newTree = new XDocument();

                using (XmlWriter writer = newTree.CreateWriter())
                {
                    // Load the style sheet.
                    XslCompiledTransform xslt = new XslCompiledTransform();
                    xslt.Load(XmlReader.Create(new StringReader(xslMarkup)));

                    // Execute the transform and output the results to a writer.
                    xslt.Transform(xmlTree.CreateNavigator(), writer);
                }

                //Console.WriteLine(newTree.ToString());

                if (dataInicial.CompareTo(dataFinal) == 0)
                {
                    nomeArquivoHTMLFormatado =
                        Constantes.NOME_ARQUIVO_HMTL.Replace(Constantes.EXTENSAO_ARQUIVO_HTML, dataInicialFormatada + Constantes.EXTENSAO_ARQUIVO_HTML);
                }
                else
                {
                    nomeArquivoHTMLFormatado =
                        Constantes.NOME_ARQUIVO_HMTL.Replace(Constantes.EXTENSAO_ARQUIVO_HTML, dataInicialFormatada + "_" + dataFinalFormatada + Constantes.EXTENSAO_ARQUIVO_HTML);
                }

                if (!Directory.Exists(Constantes.DIRETORIO_RELATORIO_GERADO))
                {
                    Directory.CreateDirectory(Constantes.DIRETORIO_RELATORIO_GERADO);
                }

                File.CreateText(Constantes.DIRETORIO_RELATORIO_GERADO + nomeArquivoHTMLFormatado).Close();

                File.WriteAllText(Constantes.DIRETORIO_RELATORIO_GERADO + nomeArquivoHTMLFormatado, newTree.ToString());
 
            }

            return nomeArquivoHTMLFormatado;
        }

        public static String gerarRelatorioXML(DateTime dataInicial, DateTime dataFinal)
        {
            String resultado = "";

            IList<ArquivoLogPonto> listaArquivosLog = obterListaArquivosLog(dataInicial, dataFinal);

            if (listaArquivosLog.Count == 0)
            {
                throw (new FileNotFoundException("Nenhum arquivo de log foi encontrado para o período " +
                                                 Util.formatarData(dataInicial, Constantes.FORMATO_DATA_COM_BARRAS) + " a " +
                                                 Util.formatarData(dataFinal, Constantes.FORMATO_DATA_COM_BARRAS)));
            }
            else
            {
                XDocument xmlTree = new XDocument(gerarXml(listaArquivosLog));
                resultado = xmlTree.ToString();
            }

            return resultado;
        }

        private static String obterNomeArquivo(DateTime data)
        {
            String resultado = "";
            String dataFormatada = Util.formatarData(data, Constantes.FORMATO_DATA_SEM_BARRAS);

            if (data.ToShortDateString().Equals(DateTime.Now.ToShortDateString()))
            {
                resultado = Constantes.NOME_ARQUIVO_LOG;
            }
            else
            {
                resultado =
                    Constantes.NOME_ARQUIVO_LOG.Replace(Constantes.EXTENSAO_ARQUIVO_XML, dataFormatada + Constantes.EXTENSAO_ARQUIVO_XML);
            }

            return resultado;
        }

        private static Dictionary<string, string> obterHashAtividades(String caminho)
        {
            Dictionary<string, string> resultado = new Dictionary<string, string>();

            XDocument docLogAtividades = XDocument.Load(@caminho);

            foreach (XElement elemento in docLogAtividades.Descendants(Constantes.ROTULO_ELEMENTO_ATIVIDADE_XML))
            {
                if (existeElementoTempoFinal(elemento))
                {
                    String atributoDescricao = elemento.Attribute(Constantes.ROTULO_ATRIBUTO_DESCRICAO).Value;
                    String tempoInicial = elemento.Descendants(Constantes.ROTULO_ELEMENTO_TEMPO_INICIAL_XML).Single().Value;
                    String tempoFinal = elemento.Descendants(Constantes.ROTULO_ELEMENTO_TEMPO_FINAL_XML).Single().Value;

                    String duracao = Util.calcularDuracao(tempoInicial, tempoFinal, false);

                    if (resultado.ContainsKey(atributoDescricao))
                    {
                        String tempoAtividade = (String)resultado[atributoDescricao];

                        duracao = Util.calcularDuracao(duracao, tempoAtividade, true);

                        resultado[atributoDescricao] = duracao;
                    }
                    else
                    {
                        resultado.Add(atributoDescricao, duracao);
                    }
                }

            }

            return resultado;
        }

        public static XElement gerarXml(IList<ArquivoLogPonto> listaArquivosLog)
        {
            IList<XElement> listaElementos = new List<XElement>();

            XElement elementRoot = new XElement(Constantes.ROTULO_ELEMENTO_RELATORIO_XML);
            foreach (ArquivoLogPonto arquivoLog in listaArquivosLog)
            {
                String dataFormatada = Util.formatarData(arquivoLog.DataCabecalho, Constantes.FORMATO_DATA_COM_BARRAS);

                Dictionary<string, string> hashAtividades = obterHashAtividades(arquivoLog.Caminho);

                if (hashAtividades != null && hashAtividades.Count > 0)
                {
                    XElement elementAtividades = new XElement(Constantes.ROTULO_ELEMENTO_ATIVIDADES_XML);

                    // Atributo data
                    elementAtividades.SetAttributeValue(Constantes.NOME_ATRIBUTO_DATA_XML, dataFormatada);

                    String tempoTotal = "00:00:00";

                    foreach (String chave in hashAtividades.Keys)
                    {
                        XElement element = new XElement(Constantes.ROTULO_ELEMENTO_ATIVIDADE_XML);

                        //Elementos  
                        element.SetElementValue(Constantes.ROTULO_ELEMENTO_ACAO_XML, chave);
                        element.SetElementValue(Constantes.ROTULO_ELEMENTO_DURACAO_XML, hashAtividades[chave]);

                        //Adiciona elemento ao elemento atividades  
                        elementAtividades.Add(element);

                        tempoTotal = Util.calcularDuracao(tempoTotal, (String)hashAtividades[chave], true);
                    }

                    // Atributo data
                    elementAtividades.SetAttributeValue(Constantes.NOME_ATRIBUTO_TEMPO_TOTAL_XML, tempoTotal);

                    elementRoot.Add(elementAtividades);
                }

            }

            return elementRoot;
        }

        private static Boolean existeElementoTempoFinal(XElement elemento)
        {
            Boolean resultado = false;

            XElement[] vetorElementos = elemento.Descendants(Constantes.ROTULO_ELEMENTO_TEMPO_FINAL_XML).ToArray();

            if (vetorElementos.Length > 0)
            {
                resultado = true;
            }

            return resultado;
        }

        private static IList<ArquivoLogPonto> obterListaArquivosLog(DateTime dataInicial, DateTime dataFinal)
        {
            double intervaloDias = (dataFinal - dataInicial).TotalDays;

            IList<DateTime> listaDatas = new List<DateTime>();
            listaDatas.Add(dataInicial);

            for (int i = 1; i <= intervaloDias; i++)
            {
                listaDatas.Add(dataInicial.AddDays(i));
            }

            IList<ArquivoLogPonto> listaArquivosLog = new List<ArquivoLogPonto>();
            foreach (DateTime data in listaDatas)
            {
                String nomeArquivoFormatado = obterNomeArquivo(data);

                if (File.Exists(Constantes.DIRETORIO_LOG + nomeArquivoFormatado))
                {
                    ArquivoLogPonto arquivoLog = new ArquivoLogPonto(nomeArquivoFormatado, data);
                    listaArquivosLog.Add(arquivoLog);
                }
            }

            return listaArquivosLog;
        }

    }

}
